#define SSE_LOAD_RGBA_16 \
 Src1 = _mm_loadu_si128((__m128i*)(offset + 0)); \
 Src2 = _mm_loadu_si128((__m128i*)(offset + 16));\
 Src3 = _mm_loadu_si128((__m128i*)(offset + 32));\
 Blue8 = _mm_shuffle_epi8(Src1, _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1));\
 Blue8 = _mm_or_si128(Blue8, _mm_shuffle_epi8(Src2, _mm_setr_epi8(-1, -1, -1, -1, 0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1)));\
 Blue8 = _mm_or_si128(Blue8, _mm_shuffle_epi8(Src3, _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 4, 8, 12, -1, -1, -1, -1)));\
 Green8 = _mm_shuffle_epi8(Src1, _mm_setr_epi8(1, 5, 9, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1));\
 Green8 = _mm_or_si128(Green8, _mm_shuffle_epi8(Src2, _mm_setr_epi8(-1, -1, -1, -1, 1, 5, 9, 13, -1, -1, -1, -1, -1, -1, -1, -1)));\
 Green8 = _mm_or_si128(Green8, _mm_shuffle_epi8(Src3, _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 1, 5, 9, 13, -1, -1, -1, -1)));\
 Red8 = _mm_shuffle_epi8(Src1, _mm_setr_epi8(2, 6, 10, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1));\
 Red8 = _mm_or_si128(Red8, _mm_shuffle_epi8(Src2, _mm_setr_epi8(-1, -1, -1, -1, 2, 6, 10, 14, -1, -1, -1, -1, -1, -1, -1, -1)));\
 Red8 = _mm_or_si128(Red8, _mm_shuffle_epi8(Src3, _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 2, 6, 10, 14, -1, -1, -1, -1)));\
 Alpha8 = _mm_shuffle_epi8(Src1, _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1));\
 Alpha8 = _mm_or_si128(Alpha8, _mm_shuffle_epi8(Src2, _mm_setr_epi8(-1, -1, -1, -1, 3, 7, 11, 15, -1, -1, -1, -1, -1, -1, -1, -1)));\
 Alpha8 = _mm_or_si128(Alpha8, _mm_shuffle_epi8(Src3, _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 3, 7, 11, 15, -1, -1, -1, -1)));\
 BL16 = _mm_unpacklo_epi8(Blue8, Zero);\
 BH16 = _mm_unpackhi_epi8(Blue8, Zero);\
 GL16 = _mm_unpacklo_epi8(Green8, Zero);\
 GH16 = _mm_unpackhi_epi8(Green8, Zero);\
 RL16 = _mm_unpacklo_epi8(Red8, Zero);\
 RH16 = _mm_unpackhi_epi8(Red8, Zero);\
 AL16 = _mm_unpacklo_epi8(Alpha8, Zero);\
 AH16 = _mm_unpackhi_epi8(Alpha8, Zero);\





#define SSE_WRITE_RGBA_16 \
 __m128i dst_b = _mm_packus_epi16(BL16_temp, BH16_temp);\
 __m128i dst_g = _mm_packus_epi16(GL16_temp, GH16_temp);\
 __m128i dst_r = _mm_packus_epi16(RL16_temp, RH16_temp);\
 __m128i dst_a = _mm_packus_epi16(AL16_temp, AH16_temp);\
 Dest1 = _mm_shuffle_epi8(dst_b, _mm_setr_epi8(0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1, -1));\
 Dest1 = _mm_or_si128(Dest1, _mm_shuffle_epi8(dst_g, _mm_setr_epi8(-1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1)));\
 Dest1 = _mm_or_si128(Dest1, _mm_shuffle_epi8(dst_r, _mm_setr_epi8(-1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1)));\
 Dest1 = _mm_or_si128(Dest1, _mm_shuffle_epi8(dst_a, _mm_setr_epi8(-1, -1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3)));\
 Dest2 = _mm_shuffle_epi8(dst_b, _mm_setr_epi8(4, -1, -1, -1, 5, -1, -1, -1, 6, -1, -1, -1, 7, -1, -1, -1));\
 Dest2 = _mm_or_si128(Dest2, _mm_shuffle_epi8(dst_g, _mm_setr_epi8(-1, 4, -1, -1, -1, 5, -1, -1, -1, 6, -1, -1, -1, 7, -1, -1)));\
 Dest2 = _mm_or_si128(Dest2, _mm_shuffle_epi8(dst_r, _mm_setr_epi8(-1, -1, 4, -1, -1, -1, 5, -1, -1, -1, 6, -1, -1, -1, 7, -1)));\
 Dest2 = _mm_or_si128(Dest2, _mm_shuffle_epi8(dst_a, _mm_setr_epi8(-1, -1, -1, 4, -1, -1, -1, 5, -1, -1, -1, 6, -1, -1, -1, 7)));\
 Dest3 = _mm_shuffle_epi8(dst_b, _mm_setr_epi8(8, -1, -1, -1, 9, -1, -1, -1, 10, -1, -1, -1, 11, -1, -1, -1));\
 Dest3 = _mm_or_si128(Dest3, _mm_shuffle_epi8(dst_g, _mm_setr_epi8(-1, 8, -1, -1, -1, 9, -1, -1, -1, 10, -1, -1, -1, 11, -1, -1)));\
 Dest3 = _mm_or_si128(Dest3, _mm_shuffle_epi8(dst_r, _mm_setr_epi8(-1, -1, 8, -1, -1, -1, 9, -1, -1, -1, 10, -1, -1, -1, 11, -1)));\
 Dest3 = _mm_or_si128(Dest3, _mm_shuffle_epi8(dst_a, _mm_setr_epi8(-1, -1, -1, 8, -1, -1, -1, 9, -1, -1, -1, 10, -1, -1, -1, 11)));\
 _mm_storeu_si128((__m128i*)(offset + 0), Dest1);\
 _mm_storeu_si128((__m128i*)(offset + 16), Dest2);\
 _mm_storeu_si128((__m128i*)(offset + 32), Dest3);\





#define SSE_LOAD_RGBA_32 \
Src1 = _mm_loadu_si128((__m128i*)(offset + 0)); \
__m128i src_blue_int = _mm_shuffle_epi8(Src1, _mm_setr_epi8(0, -1, -1, -1, 4, -1, -1, -1, 8, -1, -1, -1, 12, -1, -1, -1)); \
__m128i src_green_int = _mm_shuffle_epi8(Src1, _mm_setr_epi8(1, -1, -1, -1, 5, -1, -1, -1, 9, -1, -1, -1, 13, -1, -1, -1)); \
__m128i src_red_int = _mm_shuffle_epi8(Src1, _mm_setr_epi8(2, -1, -1, -1, 6, -1, -1, -1, 10, -1, -1, -1, 14, -1, -1, -1)); \
__m128i src_alpha_int = _mm_shuffle_epi8(Src1, _mm_setr_epi8(3, -1, -1, -1, 7, -1, -1, -1, 11, -1, -1, -1, 15, -1, -1, -1)); \




#define SSE_WRITE_RGBA_32 \
__m128i pack_32_b = _mm_packus_epi16(_mm_packus_epi32(dst_blue_int_line, Zero), Zero); \
__m128i pack_32_g = _mm_packus_epi16(_mm_packus_epi32(dst_green_int_line, Zero), Zero); \
__m128i pack_32_r = _mm_packus_epi16(_mm_packus_epi32(dst_red_int_line, Zero), Zero); \
__m128i pack_32_a = _mm_packus_epi16(_mm_packus_epi32(dst_alpha_int_line, Zero), Zero); \
dst_line = _mm_shuffle_epi8(pack_32_b, _mm_setr_epi8(0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1, -1)); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_g, _mm_setr_epi8(-1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1))); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_r, _mm_setr_epi8(-1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1))); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_a, _mm_setr_epi8(-1, -1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3))); \
_mm_storeu_si128((__m128i*)offset, dst_line); \





#define SSE_LOAD_RGBA_32F \
Src1 = _mm_loadu_si128((__m128i*)(offset + 0)); \
__m128 src_blue_float = _mm_cvtepi32_ps(_mm_shuffle_epi8(Src1, _mm_setr_epi8(0, -1, -1, -1, 4, -1, -1, -1, 8, -1, -1, -1, 12, -1, -1, -1))); \
__m128 src_green_float = _mm_cvtepi32_ps(_mm_shuffle_epi8(Src1, _mm_setr_epi8(1, -1, -1, -1, 5, -1, -1, -1, 9, -1, -1, -1, 13, -1, -1, -1))); \
__m128 src_red_float = _mm_cvtepi32_ps(_mm_shuffle_epi8(Src1, _mm_setr_epi8(2, -1, -1, -1, 6, -1, -1, -1, 10, -1, -1, -1, 14, -1, -1, -1))); \
__m128 src_alpha_float = _mm_cvtepi32_ps(_mm_shuffle_epi8(Src1, _mm_setr_epi8(3, -1, -1, -1, 7, -1, -1, -1, 11, -1, -1, -1, 15, -1, -1, -1))); \




#define SSE_WRITE_RGBA_32F \
__m128i dst_blue_int_line = _mm_cvttps_epi32(dst_blue_float_line);\
__m128i dst_red_int_line = _mm_cvttps_epi32(dst_red_float_line);\
__m128i dst_green_int_line = _mm_cvttps_epi32(dst_green_float_line);\
__m128i dst_alpha_int_line = _mm_cvttps_epi32(dst_alpha_float_line);\
__m128i pack_32_b = _mm_packus_epi16(_mm_packus_epi32(dst_blue_int_line, Zero), Zero); \
__m128i pack_32_g = _mm_packus_epi16(_mm_packus_epi32(dst_green_int_line, Zero), Zero); \
__m128i pack_32_r = _mm_packus_epi16(_mm_packus_epi32(dst_red_int_line, Zero), Zero); \
__m128i pack_32_a = _mm_packus_epi16(_mm_packus_epi32(dst_alpha_int_line, Zero), Zero); \
dst_line = _mm_shuffle_epi8(pack_32_b, _mm_setr_epi8(0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1, -1)); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_g, _mm_setr_epi8(-1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1, -1))); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_r, _mm_setr_epi8(-1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3, -1))); \
dst_line = _mm_or_si128(dst_line, _mm_shuffle_epi8(pack_32_a, _mm_setr_epi8(-1, -1, -1, 0, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3))); \
_mm_storeu_si128((__m128i*)offset, dst_line); \




void test_sse() {

    QImage src("people.png");
    src.convertTo(QImage::Format_ARGB32);
    int nBitCount = src.depth();
    int nChannel = nBitCount / 8;
    for (int y = 0; y < src.height(); y++) {
        
        int X = 0;
        __m128i Src1, Src2, Src3, Dest1, Dest2, Dest3, Blue8, Green8, Red8, Alpha8;
        __m128i BL16, BH16, GL16, GH16, RL16, RH16, AL16, AH16;
        __m128i Zero = _mm_setzero_si128();
        uchar* offset = src.scanLine(y);
        for (; X < src.width() - 12; X = X + 12, offset += 12 * nChannel) {
          
            SSE_LOAD_RGBA_16;
            //自定义处理过程
            __m128i BL16_temp = BL16;
            __m128i BH16_temp = BH16;
            __m128i GL16_temp = GL16;
            __m128i GH16_temp = GH16;
            __m128i RL16_temp = RL16;
            __m128i RH16_temp = RH16;
            __m128i AL16_temp = _mm_div_epi16 (AL16, _mm_setr_epi16(2, 2, 2, 2, 2, 2, 2, 2));
            __m128i AH16_temp = _mm_div_epi16( AH16, _mm_setr_epi16(2, 2, 2, 2, 2, 2, 2, 2));
            SSE_WRITE_RGBA_16;

        }

        for (; X < src.width(); X++, offset = offset + nChannel) {
            offset[3] = offset[3] / 2;
        }
    
    }
    src.save("sse_result.png");

}

void test_sse_32() {

    QImage src("people.png");
    src.convertTo(QImage::Format_ARGB32);
    int nBitCount = src.depth();
    int nChannel = nBitCount / 8;
    for (int y = 0; y < src.height(); y++) {

        int X = 0;
        __m128i Src1, dst_line;
        __m128i Zero = _mm_setzero_si128();
        uchar* offset = src.scanLine(y);
        for (; X < src.width() - 4; X = X + 4, offset += 4 * nChannel) {

            SSE_LOAD_RGBA_32;
            //自定义处理过程
            __m128i dst_blue_int_line = src_blue_int;
            __m128i dst_green_int_line = src_green_int;
            __m128i dst_red_int_line = src_red_int;
            __m128i dst_alpha_int_line = _mm_div_epi32( src_alpha_int, _mm_setr_epi32(2, 2, 2, 2));
            SSE_WRITE_RGBA_32;
        }

        for (; X < src.width(); X++, offset = offset + nChannel) {
            offset[3] = offset[3] / 2;
        }

    }
    src.save("sse_result.png");

}

void test_sse_32f() {

    QImage src("people.png");
    src.convertTo(QImage::Format_ARGB32);
    int nBitCount = src.depth();
    int nChannel = nBitCount / 8;
    for (int y = 0; y < src.height(); y++) {

        int X = 0;
        __m128i Src1, dst_line;
        __m128i Zero = _mm_setzero_si128();
        uchar* offset = src.scanLine(y);
        for (; X < src.width() - 4; X = X + 4, offset += 4 * nChannel) {

            SSE_LOAD_RGBA_32F;
            //自定义处理过程
            __m128 dst_blue_float_line = src_blue_float;
            __m128 dst_green_float_line = src_green_float;
            __m128 dst_red_float_line = src_red_float;
            __m128 dst_alpha_float_line = _mm_div_ps (src_alpha_float, _mm_setr_ps(2, 2, 2, 2));
            SSE_WRITE_RGBA_32F;
        }

        for (; X < src.width(); X++, offset = offset + nChannel) {
            offset[3] = offset[3] / 2;
        }

    }
    src.save("sse_result.png");
}